//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using JetBrains.Annotations;
using LargoCommon.Abstract;
using LargoCommon.Composer;
using LargoCommon.Interfaces;
using LargoCommon.Localization;
using LargoCommon.Midi;
namespace LargoCommon.Music
{
///
/// Musical file.
///
[Serializable]
public sealed class MusicalBlock : MusicalContent
{
#region Fields
///
/// Musical file.
///
private MusicalBundle musicalBundle;
///
/// Block tracks.
///
[NonSerialized]
private MusicalStrip strip;
#endregion
#region Constructors
///
/// Initializes a new instance of the MusicalBlock class.
///
public MusicalBlock() : base() {
var context = new MusicalContext(MusicalSettings.Singleton, this.Header);
this.Body = new MusicalBody(context);
this.Strip = new MusicalStrip(context);
this.ContainsMusic = false;
this.FileHeading = new FileHeading();
}
///
/// Initializes a new instance of the class.
///
/// The given header.
public MusicalBlock(MusicalHeader givenHeader) {
//// this.BlockMidi = new MusicalBlockMidi();
this.Header = givenHeader;
var context = new MusicalContext(MusicalSettings.Singleton, this.Header);
this.Body = new MusicalBody(context);
this.Strip = new MusicalStrip(context);
this.ContainsMusic = false;
this.FileHeading = new FileHeading();
}
///
/// Initializes a new instance of the class.
///
/// The mark block.
public MusicalBlock(XElement markBlock) {
Contract.Requires(markBlock != null);
if (markBlock == null) {
return;
}
var xheader = markBlock.Element("Header");
this.Header = new MusicalHeader(xheader);
this.Name = (string)markBlock.Attribute("Name");
var context = new MusicalContext(MusicalSettings.Singleton, this.Header);
XElement xbody = markBlock.Element("Body");
if (xbody == null) {
return;
}
var xstrip = markBlock.Element("Strip");
if (xstrip == null) {
return;
}
this.Strip = new MusicalStrip(xstrip, context);
this.ContainsMusic = true;
//// var xbody = markBlock.Element("Body");
//// block.Body = MusicalBodyPort.ReadMusicalBody(xbody, context);
//// this.Body = new MusicalBody(context);
this.ConvertStripToBody(true);
//// 2019/1
var setup = context.Settings;
//// 2019/12 condition is necessary - this.Body.SetHarmonicStatusFromTones(3, setup.FullHarmonization);
var xelements = xbody.Elements();
foreach (XElement xbar in xelements) {
var barNumber = (int)xbar.Attribute("Number");
MusicalBar bar = this.Body.GetBar(barNumber);
var tempo = (int)xbar.Attribute("Tempo");
bar.TempoNumber = tempo;
var xharmony = xbar.Element("Harmony");
var harmonicBar = new HarmonicBar(this.Header, xharmony) {
BarNumber = barNumber
};
bar.HarmonicBar = harmonicBar;
}
this.LoadFirstStatusToLines(); //// 2019/10
this.FileHeading = new FileHeading();
}
#endregion
#region Properties - Xml
/// Gets Xml representation.
/// Property description.
public XElement GetXElement {
get {
XElement xblock = new XElement(
"Block",
new XAttribute("Number", this.Header.Number),
new XAttribute("FileName", this.Header.FileName ?? string.Empty),
new XAttribute("Name", this.Header.Name ?? string.Empty));
XElement xheader = this.Header.GetXElement;
xblock.Add(xheader);
XElement xbody = new XElement("Body");
foreach (var bar in this.Body.Bars) {
if (bar?.HarmonicBar == null) {
continue;
}
var xbar = new XElement("Bar");
xbar.Add(new XAttribute("Number", bar.BarNumber));
var xtempo = new XAttribute("Tempo", bar.TempoNumber);
xbar.Add(xtempo);
var xharmony = bar.HarmonicBar.GetXElement;
xbar.Add(xharmony);
xbody.Add(xbar);
}
xblock.Add(xbody);
//// Prepare list for usage by MusicalLine.GetXElement,
//// status will be written as lists of bars to tracks.
if (!this.IsStripStatusOk) {
this.ConvertBodyStatusToStrip();
}
XElement xstrip = this.Strip.GetXElement;
xblock.Add(xstrip);
return xblock;
}
}
#endregion
#region Properties
///
/// Gets or sets the file heading.
///
///
/// The file heading.
///
public FileHeading FileHeading { get; set; }
///
/// Gets or sets the musical file.
///
///
/// The musical file.
///
public MusicalBundle MusicalBundle {
get => this.musicalBundle;
set => this.musicalBundle = value;
}
///
/// Gets or sets the body.
///
///
/// The body.
///
public MusicalBody Body { get; set; }
///
/// Gets or sets the block tracks.
///
///
/// The block tracks.
///
public MusicalStrip Strip {
get {
Contract.Ensures(Contract.Result() != null);
if (this.strip == null) {
throw new InvalidOperationException("Strip is null.");
}
return this.strip;
}
set => this.strip = value ?? throw new ArgumentException(LocalizedMusic.String("Argument cannot be null."), nameof(value));
}
/// Gets or sets a value indicating whether this object is body status ok.
/// True if this object is body status ok, false if not.
[UsedImplicitly]
public bool IsBodyStatusOk { get; set; }
///
/// Gets or sets a value indicating whether this object is strip status ok.
///
/// True if this object is strip status ok, false if not.
public bool IsStripStatusOk { get; set; }
///
/// Gets or sets a value indicating whether Is Selected.
///
/// Property description.
[UsedImplicitly]
public bool IsSelected { get; set; }
///
/// Gets Musical Identification.
///
/// Property description.
public IList Identification {
get {
var items = new List();
var item = new KeyValuePair(LocalizedMusic.String("Number of bars"), this.Header.NumberOfBars.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Number of lines"), this.Strip.Lines.Count.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Harmonic order"), this.Header.System.HarmonicOrder.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Rhythmic order"), this.Header.System.RhythmicOrder.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Metric"), string.Format(CultureInfo.InvariantCulture, "{0}/{1}", this.Header.Metric.MetricBeat, this.Header.Metric.MetricGround));
items.Add(item);
var musicalTempo = RhythmicSystem.ApproximateMusicalTempo(this.Header.Tempo);
item = new KeyValuePair(LocalizedMusic.String("Tempo"), string.Format(CultureInfo.InvariantCulture, "{0}({1})", this.Header.Tempo, LocalizedMusic.String("Tempo" + ((byte)musicalTempo))));
items.Add(item);
//// item = new KeyValuePair("Original file name", this.FileName);
//// items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Original division"), this.Header.Division.ToString(CultureInfo.InvariantCulture));
items.Add(item);
return items;
}
}
///
/// Gets the identification string.
///
///
/// The identification string.
///
public string IdentificationString {
get {
StringBuilder sb = new StringBuilder();
var idents = this.Identification;
foreach (var ident in idents) {
sb.AppendFormat("{0}: {1}\n", ident.Key, ident.Value);
}
return sb.ToString();
}
}
#endregion
/// Gets or sets the lines.
/// The lines.
public override List ContentLines {
get {
var ilines = (from line in this.Strip.Lines select line as IAbstractLine).ToList();
return ilines;
}
}
/// Gets or sets the harmony.
/// The harmony.
public override List ContentBars {
get {
var ibars = (from bar in this.Body.Bars select bar as IAbstractBar).ToList();
return ibars;
}
}
///
/// Gets the content elements.
///
///
/// The content elements.
///
public new IList ContentElements {
get {
var elements = this.Body.AllElements.ToList();
return elements;
}
}
#region Pattern - properties
///
/// Gets the melodic patterns.
///
///
/// The melodic patterns.
///
public IList MelodicPatterns {
get {
var body = this.Body;
var list = new List();
foreach (var bar in body.Bars) {
var pattern = new MelodicPattern(this.Header, bar) { SetName = this.FullName };
if (!pattern.IsEmpty && !pattern.ExistsInPatterns(list)) {
list.Add(pattern);
}
}
return list;
}
}
///
/// Gets the rhythmic patterns.
///
///
/// The rhythmic patterns.
///
public IList RhythmicPatterns {
get {
var body = this.Body;
var list = new List();
foreach (var bar in body.Bars) {
var pattern = new RhythmicPattern(this.Header, bar) { SetName = this.FullName };
if (!pattern.IsEmpty && !pattern.ExistsInPatterns(list)) {
list.Add(pattern);
}
}
return list;
}
}
#endregion
#region Other properties
/// Gets string with bar details.
/// General musical property.
/// Returns value.
[UsedImplicitly]
public string BarDetailsToString {
get {
var s = new StringBuilder();
s.Append(" Bar details \n");
s.Append("------------------------------------------------------\n");
var bars = from b in this.Body.Bars orderby b.BarNumber select b;
var musicTracks = (from p in this.Strip.Lines orderby p.LineIndex descending select p).ToList();
foreach (var bar in bars.Where(bar => bar != null && !bar.IsEmpty)) {
s.AppendFormat(CultureInfo.CurrentCulture, "* Bar {0,2}: *\r\n", bar.BarNumber);
foreach (var mtrack in
musicTracks.Where(mtrack => mtrack?.Tones != null && !mtrack.IsEmpty)) {
s.AppendFormat(CultureInfo.CurrentCulture, "Part {0,2}: ", mtrack.LineIndex);
var tones = mtrack.MusicalTonesInBar(bar.BarNumber);
foreach (var mt in tones.Where(mt => mt != null)) {
s.Append(mt);
}
s.AppendLine(string.Empty);
}
s.AppendLine(string.Empty);
}
return s.ToString();
}
}
#endregion
#region Static factory
///
/// Imports Midi File.
///
/// The midi block.
/// The harmonic order.
/// The rhythmic order.
/// Returns value.
public static MusicalBlock NewMusicalBlock(MidiBlock midiBlock, byte harmonicOrder, byte rhythmicOrder) {
Contract.Requires(midiBlock != null);
Contract.Requires(midiBlock.Area != null);
Contract.Requires(midiBlock.Sequence != null);
if (midiBlock.Header.Clone() is MusicalHeader musicHeader) {
musicHeader.System.HarmonicOrder = harmonicOrder;
musicHeader.System.RhythmicOrder = rhythmicOrder;
var musicalBlock = new MusicalBlock {
//// Number = midiBlock.Number,
//// BlockMidi = { OriginalBarFrom = midiBlock.Area.BarFrom, OriginalBarTo = midiBlock.Area.BarTo,
//// OriginalTimeFrom = midiBlock.MidiTimeFrom, OriginalTimeTo = midiBlock.MidiTimeTo },
Header = musicHeader
};
var context = new MusicalContext(MusicalSettings.Singleton, musicalBlock.Header);
musicalBlock.Body = new MusicalBody(context); //// 2019/02 again used!?
musicalBlock.Strip = new MusicalStrip(context);
var header = musicalBlock.Header;
foreach (var midiTrack in midiBlock.Sequence) {
var mtrack = (MidiTrack)midiTrack;
mtrack.Metric = header.Metric;
mtrack.BarDivision = MusicalProperties.BarDivision(header.Division, header.Metric.MetricBeat, header.Metric.MetricGround);
//// both delta and total is needed
//// midiTrack.Sequence.RecomputeAbsoluteTimes();
}
//// this.Strip.Lines = new List();
musicalBlock.Strip.ResetLines();
//// midiBlock.Area.BarFrom, midiBlock.Area.BarTo, midiBlock.MidiTimeFrom, midiBlock.MidiTimeTo
musicalBlock.AppendMidiTracks(midiBlock);
//// this.MusicalBlock.Division = midiTracks.Division;
var cmt = (byte)(from t in midiBlock.Sequence where t.IsMelodic select 1).Count();
var crt = (byte)(from t in midiBlock.Sequence where t.IsRhythmical select 1).Count();
musicalBlock.Header.NumberOfMelodicLines = cmt;
musicalBlock.Header.NumberOfRhythmicLines = crt;
musicalBlock.Header.NumberOfLines = cmt + crt;
return musicalBlock;
}
return null;
}
///
/// Prepares the block.
///
/// The given number of bars.
/// The given strip prototype.
///
/// Returns value.
///
[UsedImplicitly]
public static MusicalBlock PrepareBlock(int givenNumberOfBars, PackStrip givenStripPrototype) {
var header = MusicalHeader.GetDefaultMusicalHeader;
header.NumberOfBars = givenNumberOfBars;
header.Name = "Test";
header.FileName = "Test-File";
//// header.System.RhythmicOrder = firstHarBar.RhythmicStructure.Order;
var context = new MusicalContext(MusicalSettings.Singleton, header);
var strip = new MusicalStrip(context);
foreach (var prototype in givenStripPrototype.PackLines) {
var channel = MusicalProperties.ChannelForPartNumber(prototype.LineIndex);
var status = new LineStatus(
1,
prototype.Status.LineType,
prototype.Status.Instrument,
LinePurpose.Composed,
channel);
//// firstStatus.MelodicVariety = null; //// 2018/09 new MusicalVariety(MusicalSettings.Singleton);
var newTrack = new MusicalLine(status) { FirstStatus = { LocalPurpose = LinePurpose.Composed } };
strip.AddLine(newTrack, true);
}
var block = new MusicalBlock {
Header = header,
Strip = strip
};
block.Header.Number = 1;
//// 2018/10 block.ConvertStripToBody(true);
return block;
}
///
/// Defaults the block.
///
/// Returns value.
public static MusicalBlock DefaultBlock() {
var block = new MusicalBlock();
var lineStatus = new LineStatus() {
LineType = MusicalLineType.Melodic,
Instrument = new MusicalInstrument(MidiMelodicInstrument.StringEnsemble1),
Octave = MusicalOctave.TwoLine,
Loudness = MusicalLoudness.MeanLoudness,
MelodicFunction = MelodicFunction.HarmonicMotion,
MelodicShape = MelodicShape.Scales
};
block.AddContentBar(1, null);
var newline = block.AddContentLine(lineStatus);
var voice = new MusicalVoice {
Instrument = new MusicalInstrument(MidiMelodicInstrument.StringEnsemble1),
Octave = MusicalOctave.OneLine,
Loudness = MusicalLoudness.MeanLoudness,
Line = newline
};
newline.Voices = new List { voice };
newline.MainVoice = voice;
//// var bar = block.AddContentBar(1, null);
//// Convert current body back to strip!?! (Status is in elements)
block.ConvertBodyToStrip(false, false);
block.Header.NumberOfLines = block.ContentLines.Count;
block.Header.NumberOfMelodicLines = (byte)block.Header.NumberOfLines;
block.Header.NumberOfRhythmicLines = 0;
block.Header.NumberOfBars = block.ContentBars.Count;
return block;
}
#endregion
#region Add content
///
/// Adds the content bar.
///
/// The bar number.
/// The last bar.
/// Returns musical bar.
public IAbstractBar AddContentBar(int barNumber, MusicalBar lastBar) {
var bar = new MusicalBar(barNumber++, this.Body);
var chord = new HarmonicStructure(this.Header.System.HarmonicSystem, "0,4,7");
bar.HarmonicBar.SetStructure(chord);
this.Body.Bars.Add(bar);
this.Header.NumberOfBars = this.Body.Bars.Count;
MusicalElement lastElement = null;
LineStatus status = null;
foreach (var line in this.Strip.Lines) {
if (lastElement == null && lastBar != null) {
lastElement = lastBar.GetElement(line.LineIdent);
}
var musicalLine = line as MusicalLine;
if (lastElement != null) {
status = (LineStatus)lastElement.Status.Clone();
}
else {
status = (LineStatus)musicalLine.FirstStatus.Clone();
}
var element = new MusicalElement(status, lastElement) {
Bar = bar,
Line = line
};
bar.Elements.Add(element);
lastElement = element;
}
return bar;
}
///
/// Adds the line.
///
/// The given line status.
/// Returns value.
public override IAbstractLine AddContentLine(LineStatus givenStatus) {
var lines = (List)this.Strip.Lines;
var lineIndex = this.Header.NumberOfLines; //// tracks.Count() + 1;
var newLine = new MusicalLine(givenStatus) {
LineIndex = lineIndex,
Purpose = LinePurpose.Composed
};
if (givenStatus.LineType == MusicalLineType.Melodic) {
var channel = this.Strip.FindFreeChannel(newLine.LineIndex);
newLine.MainVoice.Channel = channel;
}
else {
newLine.MainVoice.Channel = MidiChannel.DrumChannel;
}
lines.Add(newLine); //// Model have to be assigned before loading
this.AddElementsForLine(newLine);
this.Header.NumberOfLines = lines.Count;
this.Strip.Context.Header.NumberOfLines = this.Header.NumberOfLines; //// ?
return newLine;
}
///
/// Adds the line.
///
/// The given line.
public void AddLine(MusicalLine givenLine) {
var lines = (List)this.Strip.Lines;
//// var lineIndex = this.Header.NumberOfLines; //// tracks.Count() + 1;
this.Header.NumberOfLines++;
lines.Add(givenLine); //// Model have to be assigned before loading
this.Header.NumberOfLines = this.ContentLines.Count;
this.AddElementsForLine(givenLine);
}
///
/// Loads the instruments to tracks.
///
public void LoadFirstStatusToLines() {
foreach (var line in this.Strip.Lines) {
foreach (var bar in this.Body.Bars) {
var point = new MusicalPoint(line.LineIndex, bar.BarNumber);
var element = this.Body.GetElement(point);
if (element?.Status?.Instrument != null && !element.Status.Instrument.IsEmpty) {
line.FirstStatus.Instrument = element.Status.Instrument; //// FixedInstrument
line.CurrentInstrument = line.FirstStatus.Instrument.Number; //// FixedInstrument
line.FirstStatus.LineType = element.Status.LineType;
//// line.FirstStatus.Instrument = new MusicalInstrument(element.Status.InstrumentNumber, element.Status.LineType);
break;
}
}
line.FirstStatus.MelodicVariety = new MusicalVariety(MusicalSettings.Singleton);
}
}
///
/// Clones the specified include tones.
///
/// If set to true [clone tracks].
/// If set to true [include tones].
///
/// Returns value.
///
public MusicalBlock Clone(bool cloneTracks, bool includeTones) {
var block = (MusicalBlock)this.Clone();
//// block.Strip.SetTracks(new List());
if (!cloneTracks) {
return block;
}
block.strip = this.Strip.Clone(includeTones);
return block;
}
///
/// Gets the harmonic stream.
///
/// The given maximum tones in chord.
/// if set to true [given full harmonization].
/// Returns value.
[UsedImplicitly]
public HarmonicStream GetHarmonicStream(byte givenMaxTonesInChord, bool givenFullHarmonization) {
this.Body.SetHarmonicStatusFromTones(givenMaxTonesInChord, givenFullHarmonization);
var harmonicStream = new HarmonicStream(this.Body.Context.Header); //// this.Name, "Derived from block"
foreach (MusicalBar bar in this.Body.Bars) {
var harBar = bar.HarmonicBar;
harmonicStream.HarmonicBars.Add(harBar);
}
return harmonicStream;
}
///
/// Sets the tempo events.
///
/// The given tempo changes.
[UsedImplicitly]
public void SetTempoEvents(IEnumerable givenTempoChanges) {
Contract.Requires(givenTempoChanges != null);
var list = new List();
var barDivision = MusicalProperties.BarDivision(this.Header.Division, this.Header.Metric.MetricBeat, this.Header.Metric.MetricGround);
var barDuration = MusicalProperties.MidiDuration(this.Header.System.RhythmicOrder, this.Header.System.RhythmicOrder, barDivision);
// ReSharper disable once LoopCanBePartlyConvertedToQuery
foreach (var change in givenTempoChanges) {
var barDeltaTime = barDuration * (change.BarNumber - 1);
var ev = new MetaTempo(0, 100) {
StartTime = barDeltaTime,
Tempo = change.TempoNumber
}; //// 100 is arbitrary number here
//// Tempo have to change just before start of bar
list.Add(ev);
}
this.Body.TempoEvents = list;
}
///
/// Deletes the line.
///
/// Index of the line.
public void DeleteLine(int lineIndex) {
this.Body.DeleteLine(lineIndex);
this.Strip.DeleteLine(lineIndex);
this.Header.NumberOfLines--;
}
///
/// Deletes the line.
///
/// The line identifier.
public void DeleteLine(Guid lineIdent) {
this.Body.DeleteLine(lineIdent);
this.Strip.DeleteLine(lineIdent);
this.Header.NumberOfLines--;
/*
var tracks = this.Strip.Lines;
var lineIndex = (from line in tracks where line.LineIdent == lineIdent select line.LineIndex).FirstOrDefault();
if (lineIndex < tracks.Count && tracks[lineIndex].LineIdent == lineIdent) {
this.DeleteLine(lineIndex);
} */
}
///
/// Append CompactMidiStrip.
///
/// The midi block.
public void AppendMidiTracks(MidiBlock midiBlock) /* CompactMidiStrip midiTracks int barNumberFrom, int barNumberTo, long timeFrom, long timeTo */
{
if (midiBlock.Sequence == null) {
return;
}
var lineIndex = this.Strip.Lines.Count;
this.Header.NumberOfBars = midiBlock.Area.BarTo - midiBlock.Area.BarFrom + 1;
var orderedToneTracks = (from mt in midiBlock.Sequence orderby mt.Octave where mt.Sequence != null select mt).ToList();
//// 2019/02 this.Body.SetTempoEventsFrom(midiBlock.MidiTimeFrom, midiBlock.MidiTimeTo, orderedToneTracks);
//// midiTrack.Sequence.RecomputeDeltaTimes();
orderedToneTracks.ForEach(midiTrack => this.AppendMidiTrack(midiTrack, lineIndex++)); //// determineBarNumbers
}
///
/// Appends the midi line.
///
/// The midi line.
/// The line number.
public void AppendMidiTrack(IMidiTrack midiTrack, int lineIndex) /* 2019/01 MusicalSection givenArea, */
{ //// ref int lineIndex, bool determineBarNumbers
Contract.Requires(midiTrack != null);
var line = new MusicalLine(midiTrack, this.Strip) /* 2019/01 givenArea, */
{
LineIndex = lineIndex
};
var tracks = (List)this.Strip.Lines;
tracks.Add(line); //// Model have to be assigned before loading
}
#endregion
#region Analysis - Public
///
/// Analyzes the tempo changes.
///
/// Returns value.
public IEnumerable AnalyzeTempoChanges() {
var changes = new List();
int lastTempoNumber = 0;
foreach (var bar in this.Body.Bars) {
/* var status = bar.Status;
if (status == null) {
continue;
} */
if (bar.TempoNumber != lastTempoNumber) {
var tc = new TempoChange(bar.BarNumber) {
TempoNumber = bar.TempoNumber
};
changes.Add(tc);
}
lastTempoNumber = bar.TempoNumber;
}
return changes;
}
#endregion
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
//// if (this.Name == null) { return string.Empty; }
var s = new StringBuilder();
s.Append("\t" + this.Header.Name.ToString(CultureInfo.CurrentCulture));
return s.ToString();
}
#endregion
#region Body-Strip Status Conversion -- see also Strip.WriteBody
///
/// Gets the line status list.
/// This methods probably do not work properly !?!?
/// Now used before composition in combination with SendStatusToTones!?
///
public void ConvertStripStatusToBody() {
if (this.Body?.Bars == null) {
return;
}
foreach (MusicalLine line in this.Strip.Lines.Where(mtrack => mtrack != null)) {
line.CurrentStatus = line.FirstStatus;
foreach (var bar in this.Body.Bars) {
var element =
(from elem in bar.Elements where elem.Line.LineIdent == line.LineIdent select elem)
.FirstOrDefault();
if (element == null) {
continue;
}
//// Status from tones only in case where there is no status defined in tracks
if (line.StatusList != null && line.StatusList.Any()) {
var status = (from ts in line.StatusList
where ts.BarNumber == bar.BarNumber
select ts).FirstOrDefault();
if (status != null) {
//// 2018/10 && trackStatus.Purpose != LinePurpose.None !?
line.CurrentStatus = status;
}
var newStatus = (LineStatus)line.CurrentStatus.Clone();
newStatus.BarNumber = bar.BarNumber;
element.Status =
newStatus; //// !!!! otherwise there are 2 different statuses for one element ...??
}
else {
element.SetElementStatusFromTones();
}
}
}
}
///
/// Sets the line status list i.e. list of bar status in each given line.
///
public void ConvertBodyStatusToStrip() {
foreach (MusicalLine line in this.Strip.Lines.Where(mtrack => mtrack != null)) {
line.StatusList = new List();
}
foreach (var bar in this.Body.Bars) {
foreach (var element in bar.Elements) {
var line = element.MusicalLine;
line.StatusList?.Add(element.Status);
}
}
}
#endregion
#region Strip-Body conversion
///
/// Converts the strip to body.
///
/// if set to true [keep status].
public void ConvertStripToBody(bool keepStatus) {
/* 2019/02
if (this.Body == null) {
this.Body = new MusicalBody(this.Strip.Context);
}
//// !?!?!? TempoEvents = this.Body.TempoEvents
//// to keep tempo-events
var tempoEvents = this.Body.TempoEvents;
*/
//// Keep original status (tempo, harmony) !?
var newBody = new MusicalBody(this.Strip);
//// 2019/10 - added missing if !!?!?!?!!!!!!!
//// if (keepStatus) {
if (this.Body != null) {
foreach (var bar in this.Body.Bars) {
var newBar = newBody.GetBar(bar.BarNumber);
if (newBar != null) {
newBar.TempoNumber = bar.TempoNumber;
newBar.HarmonicBar = (HarmonicBar)bar.HarmonicBar.Clone();
//// newBar.Status = bar.Status;
}
}
}
//// }
this.Body = newBody;
this.ConvertStripStatusToBody(); //// 2019/10 !!!!!!!
/* 2019/02
var h = this.Header;
var barMidiDuration = MusicalProperties.BarMidiDuration(h.System.RhythmicOrder, h.Metric.MetricBeat, h.Metric.MetricGround, h.Division);
if (tempoEvents != null) {
var midiEvents = tempoEvents as IList ?? tempoEvents.ToList();
if (midiEvents.Any()) {
int currentTempoNumber = 0;
foreach (var bar in this.Body.Bars) {
//// tev.BarNumber == bar.BarNumber ?
if ((from tev in midiEvents
where tev.StartTime <= bar.TimePoint && bar.TimePoint <= tev.StartTime + barMidiDuration
select tev).FirstOrDefault() is MidiEvents.MetaTempo metaTempo) {
currentTempoNumber = metaTempo.Tempo;
}
bar.Status.TempoNumber = currentTempoNumber;
}
}
} */
this.Header.NumberOfLines = this.Strip.Lines.Count;
this.Strip.Context.Header.NumberOfLines = this.Header.NumberOfLines;
//// Tones are directed by status!?? - When opening a mif-file?! - Temporary!?
if (keepStatus) {
this.ConvertStripStatusToBody();
}
}
///
/// Converts the body to strip.
///
/// if set to true [check tones].
/// if set to true [including status].
public void ConvertBodyToStrip(bool checkTones, bool includingStatus) {
this.Strip.ResetTones();
this.Strip.WriteBody(this.Body);
if (checkTones) {
this.Strip.CorrectOctaves();
}
if (includingStatus) {
this.ConvertBodyStatusToStrip();
}
}
#endregion
#region Private methods
/// Makes a deep copy of the MusicalBlock object.
/// Returns object.
private object Clone() {
var header = (MusicalHeader)this.Header.Clone();
var block = new MusicalBlock {
Header = header
//// Number = this.Header.Number
};
//// block.Strip.Lines = new Collection();
//// foreach (MusicalLine newTrack in this.MusicalTracks.Select(line => (MusicalLine)line.Clone()))
//// { block.Strip.Lines.Add(newTrack); }
return block;
}
#endregion
}
}